package com.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class CodeGenerator {
	
	private static final String base = "/home/brochen/workspaces/juxing/CodeGenerator/src/bd/";

	public static void main(String[] args) throws Exception {
		String beanName = "UserRcToken";
		String DbName = beanName.toUpperCase();
		String bdFile = "/bd/" + beanName + ".bd";
		List<ColumnDefine> list = new ArrayList<ColumnDefine>();
		
		File file = new File(base + beanName);
		if(!file.exists()) {
			file.mkdir();
		}
		
		praiseBeanDefine(bdFile, list);
		
		//生成bean
		generateBean(beanName, list);
		
		//生成ｓｑｌ
		generateTableSql(beanName, list);
		
		//生成mybatis脚本
		generateMybatisScript(beanName, list);
		
		//生成mybatis脚本
		generateDao(beanName, list);
		
	}
	private static void generateDao(String baseName, List<ColumnDefine> list) throws Exception {
		String beanName = baseName + "Bean";
		String daoName = "I" + baseName + "Dao";
		String daoImplName = baseName + "DaoImpl";
		
		//---dao
		StringBuilder daoBuilder = new StringBuilder();
		daoBuilder.append("public interface " + daoName + " {\n");
		daoBuilder.append("\n");
		daoBuilder.append("\tpublic void insert(" + beanName + " bean);");
		daoBuilder.append("\n");
		daoBuilder.append("\tpublic " + beanName + " queryById(long id);");
		daoBuilder.append("\n");
		daoBuilder.append("}");
		writeStringTOFile(base + baseName + "/" + daoName + "_java", daoBuilder.toString());
		
		//---daoimpl
		StringBuilder daoImplBuilder = new StringBuilder();
		daoImplBuilder.append("@Repository\n");
		daoImplBuilder.append("public class " + daoImplName + " extends AbstractBaseDao implements " + daoName + " {\n");
		daoImplBuilder.append("\n");
		daoImplBuilder.append("\t@Override\n");
		daoImplBuilder.append("\tpublic void insert(" + beanName + " bean) {\n");
		daoImplBuilder.append("\t\treturn this.insert(\"" + baseName + ".insert\", bean);\n");
		daoImplBuilder.append("\t}");
		daoImplBuilder.append("\n");
		daoImplBuilder.append("\t@Override\n");
		daoImplBuilder.append("\tpublic " + beanName + " queryById(long id) {\n");
		daoImplBuilder.append("\t\treturn this.selectOne(\"" + baseName + ".queryById\", id);\n");
		daoImplBuilder.append("\t}");
		daoImplBuilder.append("\n");
		daoImplBuilder.append("}");
		writeStringTOFile(base + baseName + "/" + daoImplName + "_java", daoImplBuilder.toString());
		
	}
	
	private static void generateMybatisScript(String baseName, List<ColumnDefine> list) throws Exception {
		String dbName = baseName.toUpperCase();
		StringBuilder scriptBuilder = new StringBuilder();
		
		//xml header
		scriptBuilder.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
		scriptBuilder.append("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n");
		
		scriptBuilder.append("<mapper namespace=\"" + baseName + "\">\n");
		//resultMap
		scriptBuilder.append("\t<resultMap id=\"" + baseName + "Map\" type=\"TODO Class Name\">\n");
		for(ColumnDefine cd : list) {
			scriptBuilder.append("\t\t<result column=\"" + cd.getDbName() + "\" property=\"" + cd.getName() + "\" jdbcType=\"" + cd.getJdbcType() + "\" />\n");
		}
		scriptBuilder.append("\t</resultMap>\n");
		
		//insert
		scriptBuilder.append("\n");
		scriptBuilder.append("\t<insert id=\"insert\" useGeneratedKeys=\"true\" keyProperty=\"id\" parameterType=\"long\">\n");
		scriptBuilder.append("\t\t<selectKey resultType=\"Long\" keyProperty=\"id\" order=\"AFTER\">\n");
		scriptBuilder.append("\t\t\tSELECT LAST_INSERT_ID()\n");
		scriptBuilder.append("\t\t</selectKey>\n");
		scriptBuilder.append("\t\tINSERT INTO `").append(dbName).append("`(\n");
		for(int i = 0; i < list.size(); i++) {
			ColumnDefine cd = list.get(i);
			scriptBuilder.append("\t\t\t`" + cd.getDbName() + "`");
			if(i != list.size() - 1) {
				scriptBuilder.append(",");
			}
			scriptBuilder.append("\n");
		}
		scriptBuilder.append("\t\t)VALUES(\n");
		for(int i = 0; i < list.size(); i++) {
			ColumnDefine cd = list.get(i);
			scriptBuilder.append("\t\t\t#{" + cd.getName() + "}");
			if(i != list.size() - 1) {
				scriptBuilder.append(",");
			}
			scriptBuilder.append("\n");
		}
		scriptBuilder.append("\t\t);\n");
		
		scriptBuilder.append("\t</insert>\n");
		
		//SELECT
		scriptBuilder.append("\t<select id=\"TODO\" resultMap=\"" + baseName + "Map\">\n");
		scriptBuilder.append("\t\tSELECT * FROM `" + dbName + "` WHERE ...\n");
		scriptBuilder.append("\t</select>\n");
		
		//UPDATE
		scriptBuilder.append("\n");
		scriptBuilder.append("\t<update id=\"TODO\">\n");
		scriptBuilder.append("\t\tUPDATE `" + dbName + "` SET \n");
		for(int i = 0; i < list.size(); i++) {
			ColumnDefine cd = list.get(i);
			scriptBuilder.append("\t\t\t`" + cd.getDbName() + "` = #{" + cd.getName() + "}");
			if(i != list.size() - 1) {
				scriptBuilder.append(",");
			}
			scriptBuilder.append("\n");
		}
		scriptBuilder.append("\t\t\t WHERE ...\n");
		scriptBuilder.append("\t</update>\n");
		
		//DELETE
		scriptBuilder.append("\t<delete id=\"TODOID\">\n");
		scriptBuilder.append("\t\tDELETE FROM `" + dbName + "` WHERE ...\n");
		scriptBuilder.append("\t</delete>\n");
		
		
		scriptBuilder.append("</mapper>");
		
		
		String outFile = base + baseName + "/" + baseName + ".xml";
		writeStringTOFile(outFile, scriptBuilder.toString());
	}
	private static void generateTableSql(String baseName, List<ColumnDefine> list) throws Exception {
		String dbName = baseName.toUpperCase();
		
		StringBuilder sqlBuilder = new StringBuilder();
		
		sqlBuilder.append("CREATE TABLE `").append(dbName).append("`(\n");
		
		for(ColumnDefine cd : list) {
			sqlBuilder.append("\t`").append(cd.getDbName()).append("` ").append(cd.getDbType()).append(" NOT NULL COMMENT '").append(cd.getComment()).append("',\n");
		}
		//primary
		sqlBuilder.append("\t PRIMARY KEY(``)\n");
		
		sqlBuilder.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT '表注释'");
		
		//输出到文件
		String outFile = base + baseName + "/" + baseName + "_db";
		writeStringTOFile(outFile, sqlBuilder.toString());
	}
	
	private static void generateBean(String baseName, List<ColumnDefine> list) throws Exception {
		
		String className = baseName + "Bean";
		
		StringBuilder beanBuilder = new StringBuilder();
		beanBuilder.append("public class ").append(className).append(" implements Serializable {\n");//start class
		
		beanBuilder.append("\n");
		//columns
		for(ColumnDefine cd : list) {
			beanBuilder.append("\t").append("/*").append(cd.getComment()).append("*/\n");
			beanBuilder.append("\t").append("private ").append(cd.getType()).append(" ").append(cd.getName()).append(";\n");
		}
		
		beanBuilder.append("\n");
		
		//get and set
		for(ColumnDefine cd : list) {
			///get
			beanBuilder.append("\t").append("public ").append(cd.getType()).append(" get").append(capital(cd.getName())).append("() {\n");
			beanBuilder.append("\t\t return ").append(cd.getName()).append(";\n");
			beanBuilder.append("\t}\n");
			//set
			beanBuilder.append("\t").append("public void set").append(capital(cd.getName())).append("(").append(cd.getType()).append(" ").append(cd.getName()).append(") {\n");
			beanBuilder.append("\t\t this.").append(cd.getName()).append(" = ").append(cd.getName()).append(";\n");
			beanBuilder.append("\t}\n");
			
			
			beanBuilder.append("\n");
		}
		
		beanBuilder.append("}");//end class
		
		//输出到文件
		String outFile = base + baseName + "/" + baseName + "_java";
		writeStringTOFile(outFile, beanBuilder.toString());
	}
	
	private static void writeStringTOFile(String outFile, String content) throws Exception {
		BufferedWriter bw = null;
		try {
			bw = new BufferedWriter(new FileWriter(outFile));
			
			bw.write(content);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(bw != null) {
				bw.close();
			}
		}
	}
	
	private static String capital(String str) {
		StringBuilder sb = new StringBuilder(str);
		sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
		str = sb.toString();
		return str;
	}
	
	private static void praiseBeanDefine(String bdFile, List<ColumnDefine> list) throws Exception {
		
		InputStream is = CodeGenerator.class.getResourceAsStream(bdFile);
		
		BufferedReader br = null;
		try {
			br = new BufferedReader(new InputStreamReader(is));
			
			String line;
			
			while((line = br.readLine()) != null) {
				line = line.trim();
				if(line.length() <= 0) {
					break;
				}
				
				String[] cs = line.split("\t");
				ColumnDefine cd = new ColumnDefine();
				cd.setName(cs[0]);
				cd.setDbName(getDbColumnName(cs[0]));
				cd.setComment(cs[1]);
				cd.setType(cs[2]);
				if("String".equals(cs[2])) {
					cd.setLength(Integer.parseInt(cs[3]));
				}
				setDbColumnType(cd);
				list.add(cd);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(br != null) {
				br.close();
			}
		}
		
	}

	private static void setDbColumnType(ColumnDefine cd) {
		if("int".equals(cd.getType())) {
			cd.setDbType("int(11)");
			cd.setJdbcType("INTEGER");
		} else if("long".equals(cd.getType())) {
			cd.setDbType("bigint(20)");
			cd.setJdbcType("BIGINT");
		} else if("String".equals(cd.getType())) {
			cd.setDbType("varchar(" + cd.getLength() + ")");
			cd.setJdbcType("VARCHAR");
		} 
	}
	private static String getDbColumnName(String propertyName) {
		StringBuilder sb = new StringBuilder();
		for(char c : propertyName.toCharArray()) {
			if(c >= 'A' & c <= 'Z') {
				sb.append("_");
			}
			sb.append(c);
		}
		
		return sb.toString().toUpperCase();
	}
}
